function broadcast(componentName, eventName, params) {
  this.$children.forEach(child => {
    const name = child.$options.name

    if (name === componentName) {
      child.$emit.apply(child, [eventName, params])
    } else {
      broadcast.apply(child, [componentName, eventName, params]) // 把第一行的this变为当前child
    }
  })
}

// 正常循环递归法
function findComponentsDownward(context, componentName, foundList = []) {
  const children = context.$children
  children.forEach(child => {
    const name = child.$options.name
    if (name === componentName) {
      foundList.push(child)
    }
    if (child.$children) {
      findComponentsDownward(child, componentName, foundList)
    }
  })

  return foundList
}

// 用reduce骚一把, 很骚，不用传一个foundList了
function findComponentsDownwardReduce(context, componentName) {
  return context.$children.reduce((foundList, child) => {
    if (child.$options.name === componentName) foundList.push(child)

    const foundChildren = findComponentsDownwardReduce(child, componentName)
    return foundList.concat(foundChildren)
  }, [])
}

// dispatch用了循环的方法找，因为父组件只有一个
// broadcast用了递归的方式，因为子组件是tree
export default {
  methods: {
    // 向上通知
    dispatch(componentName, eventName, params) {
      let parent = this.$parent || this.$root
      let name = parent.$options.name

      while (parent && (!name || name !== componentName)) { // 找到对应的parent
        parent = parent.$parent
        if (parent) {
          name = parent.$options.name
        }
      }

      if (parent) {
        parent.$emit.apply(parent, [eventName, params])
      }
    },

    // 向下通知
    broadcast(componentName, eventName, params) {
      broadcast.apply(this, [componentName, eventName, params])
    }
  }
}
